package net.jacqeush.mini.rpc.annotation.auto.register;
import com.aliyun.opensearch.sdk.dependencies.com.google.common.util.concurrent.ThreadFactoryBuilder;
import net.jacqeush.mini.rpc.annotation.RpcService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.Conditional;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringUtils;
import java.util.*;
import java.util.concurrent.*;

/**
 * @author Jacquesh
 * @version 1.0
 * @date 2020/10/18 2:29
 */

public class RpcAnnotasionBeanPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, BeanClassLoaderAware, ResourceLoaderAware, ApplicationContextAware {
    ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("rpcServer-pool-%d").build();
    ExecutorService executor = new ThreadPoolExecutor(16, 16,
            60L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>(Integer.MAX_VALUE),
            namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());

    private ResourceLoader resourceLoader;
    private Environment environment;
    private ClassLoader classLoader;
    private final Map<String, Object> configurations;
    private ApplicationContext applicationContext;
    public RpcAnnotasionBeanPostProcessor(Map<String, Object> configurations) {
        this.configurations = configurations;
    }
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        Set<String> basePackages = this.resolvesPackages(new HashSet((List<String>) configurations.get("basePackages")));
        Set<BeanDefinitionHolder> beanDefinitionHolders = new HashSet<>(20);
        basePackages.forEach(packages -> {
            RpcBeanDefinitionScanner scanner = RpcBeanDefinitionScanner.getScanner(beanDefinitionRegistry, RpcService.class);
            beanDefinitionHolders.addAll(scanner.doScan(packages));
        });
        //扫描完成返回bean对象生成配置类
        RpcByAnnotationStarter rpcByAnnotationStarter=new RpcByAnnotationStarter(beanDefinitionHolders);
        executor.submit(rpcByAnnotationStarter);
    }
    Set<String> resolvesPackages(Set<String> basePackages) {
        Set<String> resolvesPackages = new LinkedHashSet<>(basePackages.size());
        for (String basePackage : basePackages) {
            if (StringUtils.hasText(basePackage)) {
                String resolvesPackage = environment.resolvePlaceholders(basePackage);
                resolvesPackages.add(resolvesPackage);
            }
        }
        return resolvesPackages;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
